#include "videoPriv.h"
#include "videoIsp.h"

static int g_listBufferCreate[VIDEO_STREAM_MAX_CHN_NUMBER] = {0,0,0,0,0};

void Stream_MediaMbToImage(ENC_ImageBufInfo_t* pstDstImageBuf,MEDIA_BUFFER stSrcMediaMb)
{
    MB_IMAGE_INFO_S stMbInfo;

    if(NULL == pstDstImageBuf)
    {
        return -1;
    }

    memset(&stMbInfo,0x0,sizeof(MB_IMAGE_INFO_S));
    memset(pstDstImageBuf,0x0,sizeof(ENC_ImageBufInfo_t));

    RK_MPI_MB_GetImageInfo(stSrcMediaMb, &stMbInfo);

    int size = stMbInfo.u32Width * stMbInfo.u32Height * 3 / 2;

    pstDstImageBuf->pBuf       = RK_MPI_MB_GetPtr(stSrcMediaMb);
    pstDstImageBuf->stRect.wid = stMbInfo.u32Width;
    pstDstImageBuf->stRect.hei = stMbInfo.u32Height;
    pstDstImageBuf->stRect.wstride = stMbInfo.u32HorStride;
    pstDstImageBuf->stRect.hstride = stMbInfo.u32VerStride;
    pstDstImageBuf->len        = size;
    pstDstImageBuf->revered    = (void*)stSrcMediaMb;

    LOG_PrintError("Stream_MediaMbToImage w*h:(%d*%d) mbMediaBuf:%p \n",pstDstImageBuf->stRect.wid,
                                                                        pstDstImageBuf->stRect.hei,
                                                                        pstDstImageBuf->revered);

}


int Stream_mallocMediaMbBuffer(ENC_ImageBufInfo_t *pstDstImageBuf,ENC_ImageBufInfo_t *pstImageInfo)
{
    int iRet = 0;
    MB_IMAGE_INFO_S stMbInfo;
    MEDIA_BUFFER  stMediaMb = NULL;

    stMbInfo.enImgType    = IMAGE_TYPE_NV12;
    stMbInfo.u32Width     = pstImageInfo->stRect.wid;
    stMbInfo.u32Height    = pstImageInfo->stRect.hei;
    stMbInfo.u32HorStride = stMbInfo.u32Width;
    stMbInfo.u32VerStride = stMbInfo.u32Height;

    stMediaMb = RK_MPI_MB_CreateImageBuffer(&stMbInfo, RK_TRUE, 0);
    if (!stMediaMb) 
    {
        LOG_PrintError("RK_MPI_MB_CreateImageBuffer failed !\n");
        return NULL;
    }

    Stream_MediaMbToImage(pstDstImageBuf,stMediaMb);

    return iRet;
}

int Stream_freeMediaMbBuffer(ENC_ImageBufInfo_t *pstImageInfo)

{
    int iRet = 0;

    MEDIA_BUFFER  stMediaMb = pstImageInfo->revered;

    if(NULL != stMediaMb)
    {
        RK_MPI_MB_ReleaseBuffer(stMediaMb);
    }

    memset(pstImageInfo,0x0,sizeof(ENC_ImageBufInfo_t));
    pstImageInfo->revered = NULL;

    return iRet;
}

/* list init */
int Stream_ListInit(int chn,ENC_ImageBufInfo_t stImageInfo)
{
    int iRet = 0;

    if(chn < 0 || chn >= VIDEO_STREAM_MAX_CHN_NUMBER)
    {
        return -1;
    }

    if(1 == g_listBufferCreate[chn])
    {
        LOG_PrintError("Stream_ListInit chn-%d is already creat\n",chn);
        return -1;
    }

    StreamExt_ctl_t* pstStreamExtCtrl = &(videoCtl_g.stStreamExtCtrl[chn]);

    ENC_ImageBufCtrl_t *pstBufList  = &(pstStreamExtCtrl->stImageBufCtrl);

    /* init list */
    INIT_LIST_HEAD(& (pstBufList->emptyBuf) );
    INIT_LIST_HEAD(& (pstBufList->fullBuf) );

    /* init metux */
    iRet  = pthread_mutex_init(&(pstBufList->listMutex), NULL);
    if(iRet)
    {
        LOG_PrintError("Stream_ListInit chn-%d pthread_mutex_init failed\n",chn);
    }

    pthread_condattr_t cond_attr;
    iRet |= pthread_condattr_init(&cond_attr);
    iRet |= pthread_cond_init(&(pstBufList->listCondAttr), &cond_attr);
    if(iRet)
    {
        LOG_PrintError("Stream_ListInit chn-%d pthread_mutex_init failed\n",chn);
    }

    /* put buffer to list */
    for (int i = 0; i < VIDEO_STREAM_MAX_CNT; i++)
    {
        ENC_ImageBufInfo_t *pstImageBufInfo = &(pstBufList->stImageBufList[i].stImageBufInfo);

        /* apply memory */
        Stream_mallocMediaMbBuffer(pstImageBufInfo,&stImageInfo);

        list_add_tail(&(pstBufList->stImageBufList[i].list), &(pstBufList->emptyBuf) );
    }

    g_listBufferCreate[chn] = 1;

    return iRet;
}

int Stream_ListDeinit(int chn)
{
    int iRet = 0;

    /* no thing to do */

    return iRet;
}


int Stream_ListGetEmptyNode(int chn,ENC_listImageBufInfo_t* pstImageBuffer)
{
    int iRet = 0;
    ENC_listImageBufInfo_t *pListFrame = NULL;

    if(chn < 0 || chn >= VIDEO_STREAM_MAX_CHN_NUMBER)
    {
        //LOG_PrintError("VI_Get1080PBufferForListEmpty error !\n");
        return -1;
    }

    if(0 == g_listBufferCreate[chn])
    {
        //LOG_PrintError("Stream_ListInit chn-%d is already creat\n",chn);
        return -1;
    }

    ENC_ImageBufCtrl_t *pstBufList  = &(videoCtl_g.stStreamExtCtrl[chn].stImageBufCtrl);

    pthread_mutex_lock(&pstBufList->listMutex);

    if(!list_empty(&pstBufList->emptyBuf))
    {
        /* put empty buffer */
        pListFrame = list_first_entry(&pstBufList->emptyBuf, ENC_listImageBufInfo_t, list);
        list_del(&pListFrame->list);

        memcpy(pstImageBuffer,pListFrame,sizeof(ENC_listImageBufInfo_t) );
        pstImageBuffer->revered = pListFrame;
    }
    else
    {
        //LOG_PrintError("VI_Get1080PBufferForListEmpty error !\n");
        iRet = -1;
    }

    pthread_mutex_unlock(&pstBufList->listMutex);

    return iRet;
}

int Stream_ListPutEmptyNode(int chn,ENC_listImageBufInfo_t* pstImageBuffe)
{
    int iRet = 0;

    if(chn < 0 || chn >= VIDEO_STREAM_MAX_CHN_NUMBER)
    {
        return -1;
    }

    if(0 == g_listBufferCreate[chn])
    {
        //LOG_PrintError("Stream_ListInit chn-%d is already creat\n",chn);
        return -1;
    }

    ENC_listImageBufInfo_t *pListFrame = (ENC_listImageBufInfo_t*)pstImageBuffe->revered ;

    ENC_ImageBufCtrl_t *pstBufList  = &(videoCtl_g.stStreamExtCtrl[chn].stImageBufCtrl);

    pthread_mutex_lock(&pstBufList->listMutex);

    list_add_tail(&pListFrame->list, &pstBufList->emptyBuf);

    pthread_mutex_unlock(&pstBufList->listMutex);

    return iRet;
}

int Stream_ListGetFullNode(int chn,ENC_listImageBufInfo_t* pstImageBuffe)
{
    int iRet = 0;
    int iStatus = 1;
    ENC_listImageBufInfo_t *pListFrame = NULL;
    int iTimeOut  = 33 ;/*ms */
    struct timespec ts;
    long long tv_nsec;

    if(chn < 0 || chn >= VIDEO_STREAM_MAX_CHN_NUMBER)
    {
        return -1;
    }

    if(0 == g_listBufferCreate[chn])
    {
        //LOG_PrintError("Stream_ListInit chn-%d is already creat\n",chn);
        return -1;
    }

    ENC_ImageBufCtrl_t *pstBufList  = &(videoCtl_g.stStreamExtCtrl[chn].stImageBufCtrl);

    pthread_mutex_lock(&pstBufList->listMutex);

    while(1)
    {
        if(!list_empty(&pstBufList->fullBuf))
        {
            /* full-list have node,and get Full list node */
            pListFrame = list_first_entry(&pstBufList->fullBuf, ENC_listImageBufInfo_t, list);
            list_del(&pListFrame->list);

            memcpy(pstImageBuffe,pListFrame,sizeof(ENC_listImageBufInfo_t) );
            pstImageBuffe->revered = pListFrame;


            // LOG_PrintError("Stream_ListGetFullNode chn-%d success\n",chn);
            break;
        }
        else
        {
            if(iTimeOut > 0)
            {
                /* wait for alarm */
                clock_gettime(CLOCK_REALTIME, &ts);
                tv_nsec = ts.tv_nsec + iTimeOut * 1000000;
                ts.tv_nsec = tv_nsec % 1000000000;
                ts.tv_sec = ts.tv_sec + tv_nsec/1000000000;

                iStatus = pthread_cond_timedwait(&(pstBufList->listCondAttr), &(pstBufList->listMutex), &ts);
                if(iStatus != 0)
                {
                    iRet = -1;
                    break;
                }
            }
            else if( 0 == iTimeOut )
            {
                /* return */
                iRet = -1;
                break;
            }
            else
            {
                iStatus = pthread_cond_wait(&(pstBufList->listCondAttr), &(pstBufList->listMutex));
            }
        }
    }

    pthread_mutex_unlock(&pstBufList->listMutex);

    return iRet;


}

int Stream_ListPutFullNode(int chn,ENC_listImageBufInfo_t* pstImageBuffe)
{
    int iRet = 0;

    if(chn < 0 || chn >= VIDEO_STREAM_MAX_CHN_NUMBER)
    {
        return -1;
    }

    if(0 == g_listBufferCreate[chn])
    {
        //LOG_PrintError("Stream_ListInit chn-%d is already creat\n",chn);
        return -1;
    }

    ENC_listImageBufInfo_t *pListFrame = (ENC_listImageBufInfo_t*)pstImageBuffe->revered ;

    ENC_ImageBufCtrl_t *pstBufList  = &(videoCtl_g.stStreamExtCtrl[chn].stImageBufCtrl);

    pthread_mutex_lock(&pstBufList->listMutex);
    pListFrame->stImageBufInfo.pts = pstImageBuffe->stImageBufInfo.pts;

    list_add_tail(&pListFrame->list, &pstBufList->fullBuf);

    pthread_cond_signal(&(pstBufList->listCondAttr));

    pthread_mutex_unlock(&pstBufList->listMutex);

    //LOG_PrintError("Stream_ListPutFullNode chn-%d success\n",chn);

    return iRet;

}


int Stream_CleanBufferList(int chn)
{
    int iRet = 0;

    if(chn < 0 || chn >= VIDEO_STREAM_MAX_CHN_NUMBER)
    {
        return -1;
    }

    if(0 == g_listBufferCreate[chn])
    {
        //LOG_PrintError("Stream_ListInit chn-%d is already creat\n",chn);
        return -1;
    }

    ENC_ImageBufCtrl_t *pstBufList  = &(videoCtl_g.stStreamExtCtrl[chn].stImageBufCtrl);
    pthread_mutex_lock(&pstBufList->listMutex);

    while(!list_empty(&pstBufList->fullBuf))
    {

        /* delete full list */
        ENC_listImageBufInfo_t* pListFrame = list_first_entry(&pstBufList->fullBuf, ENC_listImageBufInfo_t, list);
        list_del(&pListFrame->list);

        /* add empty list */
        list_add_tail(&pListFrame->list, &pstBufList->emptyBuf);

    }

    pthread_mutex_unlock(&pstBufList->listMutex);

    return iRet;
}


